﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using EnvRide.Core.ObjectModel;
using CodeMadeSimple.Common.Tests;
using System.Xml;
using System;
using CodeMadeSimple.Common.Validation;
using CodeMadeSimple.Common.Tests.Validation;
using CodeMadeSimple.PropertiesManagement;
using System.IO;
using System.Threading;

namespace EnvRide.Core.UnitTests
{
    [TestFixture]
    public class EnvironmentTests : OverrideTests
    {
        private const string ARGS_OUTPUT_FILE_PATH = "ArgumentsOutputFile.xml";
        private const string INEXISTENT_DIR_FILE_PATH = "Inexistent\\Dir\\OutputFile.xml";
        private const string ENV_OUTPUT_FILE_PATH = "EnvironmentOutputFile.xml";
        private const string XML_DOCUMENT_TO_TRANSFORM_FILE_PATH = "EnvironmentTests.xml";
        
        [Test]
        public void Process()
        {
            EnvRideProject proj = new EnvRideProject();

            EnvRide.Core.ObjectModel.Environment env = new EnvRide.Core.ObjectModel.Environment();

            env.Project = proj;

            ExceptionAssert.AssertNullArgumentException("args", () => env.Process(null));

            XmlDocument doc = new XmlDocument();
            EnvRideProcessArguments args = new EnvRideProcessArguments { Document = doc };

            PropertyContext ctx = new PropertyContext("Ctx");
            ctx.AddProperty(new Property { Name = Helper.PROP_NAME, Value = Helper.PROP_VALUE });
            ctx.AddProperty(new Property { Name = "CurrentFolder", Value = "." });

            args.PropertyContainer = ctx;

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            String currentXml = doc.OuterXml;

            env.Process(args);

            AssertHasNoErrors(args);

            String rootElemName = "root";
            
            String rootElemNameIntactMsg = "Should maintain root element name intact";

            Assert.AreEqual(rootElemName, doc.DocumentElement.Name, rootElemNameIntactMsg);
            Assert.AreEqual(1, doc.DocumentElement.Attributes.Count);
            Assert.AreEqual(Helper.PROP_VALUE, doc.DocumentElement.GetAttribute(Helper.rootAttWithPropName), Helper.rootAttWithPropMsg);

            env.OutputFilePath = ".\\Output.xml";

            AssertFile.DoesNotExist("Output.xml");

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertFile.Exists("Output.xml");

            env.OutputFilePath = "${CurrentFolder}\\OutputWithProps.xml";

            AssertFile.DoesNotExist("OutputWithProps.xml");

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertFile.Exists("OutputWithProps.xml");

            env.IncludedAttributeOverrides = new AttributeOverrideIncludeCollection();

            AttributeOverrideInclude attOverInc1 = new AttributeOverrideInclude();
            attOverInc1.FilePath = "SubFolder\\FileToInclude.envRide";
            attOverInc1.EnvironmentName = "EnvToInclude1";
            attOverInc1.OverrideName = "AttOver1";
            attOverInc1.Environment = env;
            attOverInc1.Project = proj;

            env.IncludedAttributeOverrides.Add(attOverInc1);

            AttributeOverrideInclude attOverInc2 = new AttributeOverrideInclude();
            attOverInc2.FilePath = "FileToInclude.envRide";
            attOverInc2.EnvironmentName = "EnvToInclude";
            attOverInc2.OverrideName = "AttOver5";
            attOverInc2.Environment = env;
            attOverInc2.Project = proj;

            env.IncludedAttributeOverrides.Add(attOverInc2);

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);
            
            env.Process(args);

            AssertHasNoErrors(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\" />", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            env.IncludedElementOverrides = new ElementOverrideIncludeCollection();

            ElementOverrideInclude elemOverInc1 = new ElementOverrideInclude();
            elemOverInc1.FilePath = "SubFolder\\FileToInclude.envRide";
            elemOverInc1.EnvironmentName = "EnvToInclude1";
            elemOverInc1.OverrideName = "ElemOver1";
            elemOverInc1.Environment = env;
            elemOverInc1.Project = proj;

            env.IncludedElementOverrides.Add(elemOverInc1);

            ElementOverrideInclude elemOverInc2 = new ElementOverrideInclude();
            elemOverInc2.FilePath = "FileToInclude.envRide";
            elemOverInc2.EnvironmentName = "EnvToInclude";
            elemOverInc2.OverrideName = "ElemOver5";
            elemOverInc2.Environment = env;
            elemOverInc2.Project = proj;

            env.IncludedElementOverrides.Add(elemOverInc2);

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasNoErrors(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\"><includedElem1 /><includedElem5 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            env.AttributeOverrides = new AttributeOverrideCollection();

            AttributeOverride attOver1 = new AttributeOverride();
            attOver1.OverrideMode = AttributeOverrideMode.AppendAttribute;
            attOver1.AttributeName = "att1";
            attOver1.NewValue = "value1";
            attOver1.Xpath = "/root";
            attOver1.Environment = env;
            env.AttributeOverrides.Add(attOver1);

            AttributeOverride attOver2 = new AttributeOverride();
            attOver2.OverrideMode = AttributeOverrideMode.AppendAttribute;
            attOver2.AttributeName = "att2";
            attOver2.NewValue = "value2";
            attOver2.Xpath = "/root";
            attOver2.Environment = env;
            env.AttributeOverrides.Add(attOver2);

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasNoErrors(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\" att1=\"value1\" att2=\"value2\"><includedElem1 /><includedElem5 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.ElementOverrides = new ElementOverrideCollection();
            
            ElementOverride elemOver1 = new ElementOverride();
            elemOver1.OverrideMode = ElementOverrideMode.AppendChild;
            elemOver1.Xpath = "/root";
            elemOver1.NewXml = "<child/>";
            elemOver1.Environment = env;

            env.ElementOverrides.Add(elemOver1);

            ElementOverride elemOver2 = new ElementOverride();
            elemOver2.OverrideMode = ElementOverrideMode.AppendChild;
            elemOver2.Xpath = "/root";
            elemOver2.NewXml = "<child/>";
            elemOver2.Environment = env;

            env.ElementOverrides.Add(elemOver2);

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasNoErrors(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\" att1=\"value1\" att2=\"value2\"><includedElem1 /><includedElem5 /><child /><child /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            attOver1.Xpath = "/root1";

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);
            
            AssertHasErrors(args, new[] { GetXPathDidNotReturnNodesMessage("/root1") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\" att2=\"value2\"><includedElem1 /><includedElem5 /><child /><child /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            attOver2.Xpath = "/root2";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\"><includedElem1 /><includedElem5 /><child /><child /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            AssertHasErrors(args, new[] { GetXPathDidNotReturnNodesMessage("/root1"), GetXPathDidNotReturnNodesMessage("/root2") });

            elemOver1.Xpath = "/root3";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetXPathDidNotReturnNodesMessage("/root1"), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\"><includedElem1 /><includedElem5 /><child /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            elemOver2.Xpath = "/root4";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);
            
            AssertHasErrors(args, new[] { GetXPathDidNotReturnNodesMessage("/root1"), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\"><includedElem1 /><includedElem5 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            attOver1.Xpath = "/root";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt1=\"includedValue1\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem1 /><includedElem5 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            attOverInc1.OverrideName = "InvalidOverride";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem1 /><includedElem5 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            elemOverInc2.EnvironmentName = "InvalidEnvironment";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            proj.IncludedAttributeOverrides = new AttributeOverrideIncludeCollection();

            AttributeOverrideInclude projAttOverInc1 = new AttributeOverrideInclude();
            projAttOverInc1.FilePath = "SubFolder\\FileToInclude.envRide";
            projAttOverInc1.EnvironmentName = "EnvToInclude1";
            projAttOverInc1.OverrideName = "AttOver2";
            projAttOverInc1.Project = proj;

            proj.IncludedAttributeOverrides.Add(projAttOverInc1);

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt2=\"includedValue2\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            AttributeOverrideInclude projAttOverInc2 = new AttributeOverrideInclude();
            projAttOverInc2.FilePath = "FileToInclude.envRide";
            projAttOverInc2.EnvironmentName = "EnvToInclude";
            projAttOverInc2.OverrideName = "AttOver6";
            projAttOverInc2.Project = proj;

            proj.IncludedAttributeOverrides.Add(projAttOverInc2);

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt2=\"includedValue2\" includedAtt6=\"includedValue6\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            proj.IncludedElementOverrides = new ElementOverrideIncludeCollection();

            ElementOverrideInclude projElemOverInc1 = new ElementOverrideInclude();
            projElemOverInc1.FilePath = "SubFolder\\FileToInclude.envRide";
            projElemOverInc1.EnvironmentName = "EnvToInclude1";
            projElemOverInc1.OverrideName = "ElemOver2";
            projElemOverInc1.Project = proj;

            proj.IncludedElementOverrides.Add(projElemOverInc1);

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt2=\"includedValue2\" includedAtt6=\"includedValue6\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem2 /><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            ElementOverrideInclude projElemOverInc2 = new ElementOverrideInclude();
            projElemOverInc2.FilePath = "FileToInclude.envRide";
            projElemOverInc2.EnvironmentName = "EnvToInclude";
            projElemOverInc2.OverrideName = "ElemOver6";
            projElemOverInc2.Project = proj;

            proj.IncludedElementOverrides.Add(projElemOverInc2);

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt2=\"includedValue2\" includedAtt6=\"includedValue6\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem2 /><includedElem6 /><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            projAttOverInc1.OverrideName = "InvalidOverride1";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(projAttOverInc1.OverrideName), GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt6=\"includedValue6\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem2 /><includedElem6 /><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);

            projElemOverInc1.OverrideName = "InvalidOverride2";

            args.HasErrors = false;

            Appender.Clear();

            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            env.Process(args);

            AssertHasErrors(args, new[] { GetOverrideNotFoundMessage(projAttOverInc1.OverrideName), GetOverrideNotFoundMessage(attOverInc1.OverrideName), GetOverrideNotFoundMessage(projElemOverInc1.OverrideName), GetEnvironmentNotFoundMessage("InvalidEnvironment", elemOverInc2, args), GetXPathDidNotReturnNodesMessage("/root2"), GetXPathDidNotReturnNodesMessage("/root3"), GetXPathDidNotReturnNodesMessage("/root4") });

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" includedAtt6=\"includedValue6\" includedAtt5=\"includedValue5\" att1=\"value1\"><includedElem6 /><includedElem1 /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);
        }

        [Test]
        public void Process_CreateOutputFileDirectory()
        {
            EnvRideProject proj = new EnvRideProject();

            EnvRide.Core.ObjectModel.Environment env = new ObjectModel.Environment();

            env.Project = proj;

            XmlDocument doc = new XmlDocument();
            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            EnvRideProcessArguments args = new EnvRideProcessArguments();
            args.Document = doc;
            args.OutputFilePath = INEXISTENT_DIR_FILE_PATH;
            args.CreateOutputFileDirectory = false;

            Assert.Throws<DirectoryNotFoundException>(() => env.Process(args));

            args.CreateOutputFileDirectory = true;

            env.Process(args);
        }

        [Test]
        public void Process_OutputFilePath()
        {
            EnvRideProject proj = new EnvRideProject();

            EnvRide.Core.ObjectModel.Environment env = new ObjectModel.Environment();

            env.Project = proj;

            XmlDocument doc = new XmlDocument();
            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            EnvRideProcessArguments args = new EnvRideProcessArguments();
            args.Document = doc;

            env.Process(args);

            // If no output file is supplied, should not create any file.
            AssertFile.DoesNotExist(ARGS_OUTPUT_FILE_PATH);
            AssertFile.DoesNotExist(ENV_OUTPUT_FILE_PATH);

            env.OutputFilePath = ENV_OUTPUT_FILE_PATH;

            env.Process(args);

            // If the environment output file path was supplied, should create the file
            AssertFile.DoesNotExist(ARGS_OUTPUT_FILE_PATH);
            AssertFile.Exists(ENV_OUTPUT_FILE_PATH);

            File.Delete(ENV_OUTPUT_FILE_PATH);

            args.OutputFilePath = ARGS_OUTPUT_FILE_PATH;

            env.Process(args);

            // If the argument output file path was supplied, should override the one from the environment
            AssertFile.Exists(ARGS_OUTPUT_FILE_PATH);
            AssertFile.DoesNotExist(ENV_OUTPUT_FILE_PATH);

            File.Delete(ARGS_OUTPUT_FILE_PATH);

            env.OutputFilePath = null;

            env.Process(args);

            // If the argument output file path was supplied and the environment output file was not, it should use the argument output file path
            AssertFile.Exists(ARGS_OUTPUT_FILE_PATH);
            AssertFile.DoesNotExist(ENV_OUTPUT_FILE_PATH);
        }

        [Test]
        public void Process_SaveOutputFileOnlyIfItHasChanges()
        {
            EnvRideProject proj = new EnvRideProject();

            EnvRide.Core.ObjectModel.Environment env = new ObjectModel.Environment();

            env.Project = proj;

            XmlDocument doc = new XmlDocument();
            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            EnvRideProcessArguments args = new EnvRideProcessArguments();
            args.Document = doc;

            args.OutputFilePath = ARGS_OUTPUT_FILE_PATH;

            env.Process(args);

            // Asserts that if the SaveOutputFileOnlyIfItHasChanges is false, it will write to the output file even if there are no differences
            args.SaveOutputFileOnlyIfItHasChanges = false;

            FileInfo outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            DateTime lastWrite = outputFile.LastWriteTime;

            Thread.Sleep(100);

            env.Process(args);

            outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            Assert.Greater(outputFile.LastWriteTime, lastWrite, "Should have setted the LastWriteTime since the SaveOutputFileOnlyIfItHasChanges arguments property returned false.");

            lastWrite = outputFile.LastWriteTime;

            // Asserts that if the SaveOutputFileOnlyIfItHasChanges is true, it will write to the output file path only if it has changes
            args.SaveOutputFileOnlyIfItHasChanges = true;

            env.Process(args);

            outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            Assert.AreEqual(lastWrite, outputFile.LastWriteTime, "Since there are no changes, it should not write to the file.");

            doc.LoadXml(doc.OuterXml.Replace("root", "rOot"));

            env.Process(args);

            outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            Assert.Greater(outputFile.LastWriteTime, lastWrite, "Since the content changed, it should have written the file.");

            lastWrite = outputFile.LastWriteTime;

            env.Process(args);

            outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            Assert.AreEqual(lastWrite, outputFile.LastWriteTime, "Since there are no changes, it should not write to the file.");

            doc.LoadXml(doc.OuterXml.Replace("rOot", "rOots"));

            env.Process(args);

            outputFile = new FileInfo(ARGS_OUTPUT_FILE_PATH);

            Assert.Greater(outputFile.LastWriteTime, lastWrite, "Since the content changed, it should have written the file.");
        }

        public override void TearDown()
        {
            base.TearDown();

            String inexistentDir = Path.GetDirectoryName(INEXISTENT_DIR_FILE_PATH);

            if (Directory.Exists(inexistentDir))
                Directory.Delete(inexistentDir, true);

            File.Delete(ARGS_OUTPUT_FILE_PATH);
            File.Delete(ENV_OUTPUT_FILE_PATH);
            File.Delete("Output.xml");
            File.Delete("OutputWithProps.xml");
        }

        [Test]
        public void ProcessWithBaseEnvironments()
        {
            EnvRideProject proj = EnvRideProject.Deserialize("ProcessWithBaseEnvironments.envRide");

            EnvRide.Core.ObjectModel.Environment env = proj.Environments["Env1"];

            XmlDocument doc = new XmlDocument();
            EnvRideProcessArguments args = new EnvRideProcessArguments { Document = doc };
            doc.Load(XML_DOCUMENT_TO_TRANSFORM_FILE_PATH);

            PropertyContext ctx = new PropertyContext("Ctx");
            ctx.AddProperty(new Property { Name = Helper.PROP_NAME, Value = Helper.PROP_VALUE });
            ctx.AddProperty(new Property { Name = "CurrentFolder", Value = ".\\" });

            args.PropertyContainer = ctx;

            env.Process(args);

            Assert.AreEqual(String.Format("<?xml version=\"1.0\" encoding=\"utf-8\"?><root {0}=\"{1}\" baseBaseBaseAtt=\"baseBaseBaseValue\" baseBaseAtt=\"baseBaseValue\" baseAtt=\"baseValue\"><baseBaseBaseElem /><baseBaseElem /><baseElem /></root>", Helper.rootAttWithPropName, Helper.PROP_VALUE), doc.OuterXml);
        }

        [Test]
        public void Serialization()
        {
            throw new NotImplementedException();
        }

        [Test]
        public void Validate()
        {
            EnvRide.Core.ObjectModel.Environment env = new ObjectModel.Environment();

            ValidationResult result = env.Validate();

            ValidationResult expectedResult = new ValidationResult(env);
            expectedResult.AddMessage(new RequiredValueValidationMessage("Name"));

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.Name = "Name";

            result = env.Validate();
            expectedResult = new ValidationResult(env);

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.AttributeOverrides = new AttributeOverrideCollection();

            result = env.Validate();
            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.AttributeOverrides.Add(new AttributeOverride());

            ValidationResult attOverResults = new ValidationResult("AttributeOverrides");

            expectedResult.AddChildResult(attOverResults);

            ValidationResult attOver1Result = new ValidationResult(env.AttributeOverrides[0]);
            attOver1Result.AddMessage(new RequiredValueValidationMessage("Xpath"));
            attOver1Result.AddMessage(new RequiredValueValidationMessage("AttributeName"));

            attOverResults.AddChildResult(attOver1Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.AttributeOverrides.Add(new AttributeOverride());

            ValidationResult attOver2Result = new ValidationResult(env.AttributeOverrides[1]);
            attOver2Result.AddMessage(new RequiredValueValidationMessage("Xpath"));
            attOver2Result.AddMessage(new RequiredValueValidationMessage("AttributeName"));

            attOverResults.AddChildResult(attOver2Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.ElementOverrides = new ElementOverrideCollection();

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.ElementOverrides.Add(new ElementOverride());

            ValidationResult elemOversResult = new ValidationResult("ElementOverrides");
            expectedResult.AddChildResult(elemOversResult);

            ValidationResult elemOver1Result = new ValidationResult(env.ElementOverrides[0]);
            elemOver1Result.AddMessage(new RequiredValueValidationMessage("Xpath"));

            elemOversResult.AddChildResult(elemOver1Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.ElementOverrides.Add(new ElementOverride());

            ValidationResult elemOver2Result = new ValidationResult(env.ElementOverrides[1]);
            elemOver2Result.AddMessage(new RequiredValueValidationMessage("Xpath"));

            elemOversResult.AddChildResult(elemOver2Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.IncludedAttributeOverrides = new AttributeOverrideIncludeCollection();

            env.IncludedAttributeOverrides.Add(new AttributeOverrideInclude());

            ValidationResult incAttOversResult = new ValidationResult("IncludedAttributeOverrides");
            expectedResult = new ValidationResult(env);
            expectedResult.AddChildResult(incAttOversResult);
            expectedResult.AddChildResult(attOverResults);
            expectedResult.AddChildResult(elemOversResult);

            ValidationResult attOverInc1Result = new ValidationResult(env.IncludedAttributeOverrides[0]);
            attOverInc1Result.AddMessage(new RequiredValueValidationMessage("EnvironmentName"));

            incAttOversResult.AddChildResult(attOverInc1Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.IncludedAttributeOverrides.Add(new AttributeOverrideInclude());

            ValidationResult attOverInc2Result = new ValidationResult(env.IncludedAttributeOverrides[1]);
            attOverInc2Result.AddMessage(new RequiredValueValidationMessage("EnvironmentName"));

            incAttOversResult.AddChildResult(attOverInc2Result);

            env.IncludedElementOverrides = new ElementOverrideIncludeCollection();
            env.IncludedElementOverrides.Add(new ElementOverrideInclude());

            ValidationResult incElemOversResult = new ValidationResult("IncludedElementOverrides");

            ValidationResult elemOverInc1Result = new ValidationResult(env.IncludedElementOverrides[0]);
            elemOverInc1Result.AddMessage(new RequiredValueValidationMessage("EnvironmentName"));
            incElemOversResult.AddChildResult(elemOverInc1Result);

            expectedResult = new ValidationResult(env);
            expectedResult.AddChildResult(incAttOversResult);
            expectedResult.AddChildResult(incElemOversResult);
            expectedResult.AddChildResult(attOverResults);
            expectedResult.AddChildResult(elemOversResult);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);

            env.IncludedElementOverrides.Add(new ElementOverrideInclude());
            
            ValidationResult elemOverInc2Result = new ValidationResult(env.IncludedElementOverrides[1]);
            elemOverInc2Result.AddMessage(new RequiredValueValidationMessage("EnvironmentName"));
            incElemOversResult.AddChildResult(elemOverInc2Result);

            result = env.Validate();

            ValidationResultTests.AssertValidationResult(result, expectedResult);
        }
    }
}
